<?php

/**
 * File Class
 * It provides a layer in order to use files
 *
 * @copyright inovia
 */
class File {
	private $handle;          // pointer on the file
	private $fileName;        // name of the file

	private $compression;     // type of compression for the destination file
	// it can be 'gz' (gzip), 'bz' (bzip2), 'f' (none)



	/*
	 * It opens the file $fileName with the mode $mode.
	 *
	 * If we try to create this file (all the modes except 'r', 'rt' and 'rb'),
	 * we first try to create all the directories in which this file is.
	 *
	 * @param : $fileName - string - Path to the file
	 * @param : $mode - string - Mode used to open the file
	 */
	public function __construct($fileName, $mode="r", $compression=null) {
		$this->fileName = $fileName;


		// we try to detect the compression mode
		// if there's a problem, we don't use compression
		switch($compression) {
			case "gzip":
				$this->compression = "gz";
				break;
			case "bzip2":
				$this->compression = "bz";
				break;
			default:
				$this->compression = "f";
				break;
		}


		// if the mode is not 'r' (or 'rb'/'rt'), we have to attempt to create the directory needed
		// first, we will get the directory path from the given fileName
		// then, we will verify whether the directory exists
		// finally, we will create it if the directory does not exist
		switch($mode) {
			case "r":
			case "rt":
			case "rb":
				break;
			default:
				$dirTab = explode("/",$this->fileName);
				$curDir = "";
				for($i=0;$i<count($dirTab)-1;$i++) {
					$curDir .= $dirTab[$i]."/";
					if(!is_dir($curDir)) {
						if(@mkdir($curDir,0755)===FALSE) {
							throw new Exception("Unable to create the directory \"".$curDir."\" in order to open the file \"".$this->fileName."\" with the mode '".$mode."'.");
						}
					}
				}
				break;
		}

		if(($this->handle = eval("return @".$this->compression."open(\$this->fileName,\$mode);"))===FALSE) {
			throw new Exception("Unable to open the file \"".$this->fileName."\" with the mode '".$mode."'.");
		}
	}



	/*
	 * @return : unsigned int - Size of the file
	 */
	public function size() {
		return filesize($this->fileName);
	}



	/*
	 * It tests whether we are at the end of the file or not.
	 *
	 * @return : bool - True if we are at the end, false otherwise
	 */
	public function eof() {
		return feof($this->handle);
	}



	/*
	 * It tries to write the given string in the file.
	 *
	 * @param : $stringToWrite - string - The string we have to write in the file
	 * @return : unsigned int - The number of bytes written
	 */
	public function writeAll($stringToWrite) {
		try {
			return $this->writeLgth($stringToWrite,strlen($stringToWrite));
		} catch(Exception $e) {
			throw new Exception($e->getMessage());
		}
	}




	/*
	 * It tries to write the given string in the file,
	 * but writing will stop after length bytes have been written
	 * or the end of string is reached, whichever comes first.
	 *
	 * @param : $stringToWrite - string - The string we have to write in the file
	 * @param : $lengthToWrite - unsigned int - The maximum of bytes of the string which could be written
	 * @return : unsigned int - The number of bytes written
	 */
	public function writeLgth($stringToWrite,$lengthToWrite) {
		if(($lengthWrited = eval("return @".$this->compression."write(\$this->handle,\$stringToWrite,\$lengthToWrite);"))===FALSE) {
			throw new Exception("Unable to write ".$lengthToWrite." bytes of \"".$stringToWrite."\" in the file \"".$this->fileName."\".");
		}
		return $lengthWrited;
	}






	/*
	 * It tries to read all bytes of the file.
	 *
	 * @return : string - the read string
	 */
	public function readAll() {
		try {
			return $this->readLgth($this->size());
		} catch(Exception $e) {
			throw new Exception($e->getMessage());
		}
	}
	 



	 
	/*
	 * It tries to read the specified number of bytes of the file,
	 * but reading will stop after length bytes have been read
	 * or the end of file is reached, whichever comes first.
	 *
	 * @param : $lengthToRead - unsigned int - the maximum of bytes which could be read
	 * @return : string - the read string
	 */
	public function readLgth($lengthToRead) {
		if(($contents = eval("return @".$this->compression."read(\$this->handle,\$lengthToRead);"))===FALSE) {
			throw new Exception("Unable to read ".$lengthToRead." bytes of the file \"".$this->fileName."\".");
		}
		return $contents;
	}




	/*
	 * @return : unsigned int - Modification time of the file
	 */
	public function modificationTime() {
		return filemtime($this->fileName);
	}





	/*
	 * @return : unsigned int - Last access time of the file
	 */
	public function accessTime() {
		return fileatime($this->fileName);
	}





	/*
	 * It tries to set the file position indicator at the offset defined.
	 *
	 * @param : $offset - int - Offset defining the new position
	 * @param : $whence - (SEEK_SET|SEEK_CUR|SEEK_END|null) - Mode
	 */
	public function seek($offset,$whence) {
		switch($whence) {
			case "SEEK_SET":
			case "SEEK_CUR":
			case "SEEK_END":
				break;
			default:
				$whence = "SEEK_SET";
		}
		 
		if(fseek($this->fileName,$whence)==-1) {
			throw new Exception("Unable to set the file position indicator at ".$offset." with the mode ".$whence." on the file \"".$this->fileName."\".");
		}
	}







	/*
	 * It closes the file opened.
	 */
	public function __destruct() {
		if(eval("return @".$this->compression."close(\$this->handle);")===FALSE) {
			throw new Exception("Unable to close the file \"".$this->fileName."\".");
		}
	}
}

function fcopy($srcfile, $dstfile, $verbose = false){
	$dirTab = explode("/",$dstfile);
	$curDir = "";
	for($i=0;$i<count($dirTab)-1;$i++) {
		$curDir .= $dirTab[$i]."/";
		if(!is_dir($curDir)) {
			if(@mkdir($curDir,0755)===FALSE) {
				throw new Exception("Unable to create the directory \"".$curDir);
			}
		}
	}
	if($verbose) echo "Copying '$srcfile' to '$dstfile'...";
	if(copy($srcfile, $dstfile)) {
		touch($dstfile, filemtime($srcfile)); //$num++;
		if($verbose) echo "OK\n";
	}
	else echo "Error: File '$srcfile' could not be copied!\n";

	 
}

/**
 *
 * @param $srcdir
 * @param $dstdir
 * @param $verbose
 * @return string
 */

function dircopy($srcdir, $dstdir, $verbose = false) {


    
	$num = 0;
	$dirTab = explode("/",$dstdir);
	$curDir = "";
	for($i=0;$i<count($dirTab);$i++) {
		$curDir .= $dirTab[$i]."/";
		if(strpos($srcdir, ".svn") === false && !is_dir($curDir)) {
			if(@mkdir($curDir,0755)===FALSE) {
				throw new Exception("Unable to create the directory \"".$curDir);
			} elseif($verbose) {
				echo "<pre>curDir :  $curDir</pre>";
			}
		}
	}

	if(strpos($srcdir, ".svn") === false && $curdir = opendir($srcdir)) {
		if($verbose) echo "1";
		while($file = readdir($curdir)) {
			if($verbose) echo "2";
			if($file != '.' && $file != '..') {
				if($verbose) echo "3";
				$srcfile = $srcdir . '/' . $file;
				$dstfile = $dstdir . '/' . $file;
				if($verbose) echo "<br/>SRCFILE :  ".$srcfile;
				if(is_file($srcfile) && is_readable($srcfile)) {
					if($verbose) echo " 4.1 ";
					if(is_file($dstfile)) $ow = filemtime($srcfile) - filemtime($dstfile); else $ow = 1;
					if(true) {
						 
						if($verbose) echo "5";
						if($verbose) echo "Copying '$srcfile' to '$dstfile'...";
						if(@copy($srcfile, $dstfile)) {
							touch($dstfile, filemtime($srcfile)); $num++;
							if($verbose) echo "OK\n";
						}
						else{
							$ex = explode('/',$srcfile);
							if($ex[count($ex)-1] != 'Thumbs.db') echo "Error: File '$srcfile' could not be copied!\n";
						}
					}
					 
				}
				else if(is_dir($srcfile)) {
					if($verbose) echo " 4.2 ";
					$num += dircopy($srcfile, $dstfile, $verbose);
				}else{
					if($verbose) echo " 4.3 ";
				}
			}
		}
		closedir($curdir);
	}
	return $num;
}
?>
